package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deer.wms.base.system.dao.AreaInfoMapper;
import com.deer.wms.base.system.dao.ErpBackRecordMapper;
import com.deer.wms.base.system.dao.ItemInfoMapper;
import com.deer.wms.base.system.dao.ShelfInfoMapper;
import com.deer.wms.base.system.model.*;
import com.deer.wms.base.system.model.Area.AreaInfo;
import com.deer.wms.base.system.model.Cell.CellInfo;
import com.deer.wms.base.system.model.Item.ItemInfo;
import com.deer.wms.base.system.model.Shelf.ShelfInfo;
import com.deer.wms.base.system.model.Supplier.SupplierManage;
import com.deer.wms.base.system.model.erp.*;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.base.system.service.ErpService;
import com.deer.wms.base.system.service.ItemInfoService;
import com.deer.wms.busine.tactic.model.RouteTactic;
import com.deer.wms.busine.tactic.model.RouteTacticCriteria;
import com.deer.wms.busine.tactic.service.RouteTacticService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.dao.InventoryMapper;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.core.service.QueryCriteria;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.BeanUtils;
import com.deer.wms.project.root.util.CollectionUtils;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.project.root.util.StringUtils;
import com.deer.wms.review.manage.model.BillRecord;
import com.deer.wms.review.manage.service.BillRecordService;
import com.deer.wms.review.manage.service.CaseMasterService;
import com.deer.wms.system.manage.dao.CustomerMapper;
import com.deer.wms.system.manage.dao.WareInfoMapper;
import com.deer.wms.system.manage.model.customer.Customer;
import com.deer.wms.system.manage.model.organization.Organization;
import com.deer.wms.system.manage.model.ware.WareInfo;
import com.deer.wms.system.manage.service.*;
import com.deer.wms.ware.task.model.pushErp.StrategyErpService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.PickTaskMapper;
import com.deer.wms.ware.task.dao.SoDetailMapper;
import com.deer.wms.ware.task.dao.SoMasterMapper;
import com.deer.wms.ware.task.model.*;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSo;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSoDeliveryAddress;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSoShippingAddress;
import com.deer.wms.ware.task.model.SO.CreateSo.CreateSoSkuDetail;
import com.deer.wms.ware.task.model.SO.*;
import com.deer.wms.ware.task.model.SO.vo.SoDetailVo;
import com.deer.wms.ware.task.model.SO.vo.SoMasterVo;
import com.deer.wms.ware.task.model.out.OutMaster;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by guo on 2020/02/02.
 */
@Service
@Transactional
public class SoMasterServiceImpl extends SuperServiceImpl<SoMasterMapper, SoMaster> implements SoMasterService {

    @Autowired
    private SoMasterMapper soMasterMapper;

    @Autowired
    private ValidatorService validatorService;

    @Autowired
    private SoMasterService soMasterService;

    @Autowired
    private SoDetailService soDetailService;

    @Autowired
    private CaseMasterService caseMasterService;

    @Autowired
    private SoMasterFileService soMasterFileService;

    @Autowired
    private SoDetailFileService soDetailFileService;
    @Autowired
    private RouteTacticService routeTacticService;

    @Autowired
    private BillRecordService billRecordService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private PickTaskMapper pickTaskMapper;
    @Autowired
    private SoDetailMapper soDetailMapper;
    @Autowired
    private ErpBackRecordMapper erpBackRecordMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private ItemInfoMapper itemInfoMapper;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private OutMasterService outMasterService;
    @Autowired
    private PushErpService pushErpService;
    @Autowired
    private CellInfoService cellInfoService;

    @Autowired
    private CodeRuleService codeRuleService;
    @Autowired
    private AsyncService asyncService;

    @Autowired
    private RgProdOutRecordService rgProdOutRecordService;

    @Autowired
    private InventoryMapper inventoryMapper;
    @Autowired
    private ShelfInfoMapper shelfInfoMapper;
    @Autowired
    private AreaInfoMapper areaInfoMapper;
    @Autowired
    private SoLogService soLogService;

    @Override
    public List<SoMasterDto> findList(SoMasterCriteria criteria) {
        return soMasterMapper.findList(criteria);
    }

    @Override
    public List<SoMasterDto> findByWaveId(Integer id, Integer wareId) {
        return soMasterMapper.findByWaveId(id, wareId);
    }


    @Override
    public SoMasterDto getSeedingByItemCode(String itemCode, Integer wareId, Integer waveMasterId) {
        List<SoMasterDto> list = soMasterMapper.getSeedingByItemCode(itemCode, wareId, waveMasterId);
        if (list.size() > 0) {

            return list.get(0);
        } else {
            return null;
        }
    }


    @Override
    public void deleteByBillNo(String billNo) {
        soMasterMapper.deleteByBillNo(billNo);
    }

    @Override
    public void closeById(Integer id) {
        SoMaster soMaster = soMasterService.getById(id);
        //拣货任务也需要关闭
        List<PickTask> pickTasks = pickTaskService.getListByField("so_master_code", soMaster.getBillNo());
        for (PickTask pickTask : pickTasks) {
            if (ObjectUtil.equal(WareTaskConstant.PICK_STATE_PARTPICK, pickTask.getState()) ||
                    ObjectUtil.equal(WareTaskConstant.PICK_STATE_PROCESSING, pickTask.getState())) {
                pickTaskService.cancelPickTask(pickTask);
            }
        }

        soMaster.setState(WareTaskConstant.OUT_STATE_CLOSE2);
        List<SoDetail> soDetails = soDetailService.getListByField("bill_no", soMaster.getBillNo());
        for (SoDetail soDetail : soDetails) {
            if (ObjectUtil.equal(WareTaskConstant.OUT_STATE_INIT, soDetail.getState()) || ObjectUtil.equal(WareTaskConstant.OUT_STATE_DOING,
                    soDetail.getState())) {
                soDetail.setState(WareTaskConstant.OUT_STATE_CLOSE2);
            }
        }
        soDetailService.updateBatchById(soDetails);
        soMasterService.updateById(soMaster);
    }


    @Override
    public void createSoMaster(SoData soData, CurrentUser currentUser) {
        /**
         *  新建SO单据
         */
        SoMaster soMaster = soData.getSoMaster();
        String tableName = "so_master";
        Integer nextId = validatorService.getNextId(tableName);

        String billNo = "SO" + "-" + nextId;
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();

        if (soData.getBillSource() == 1 || soData.getBillSource() == 3 || soData.getBillSource() == 4) {
            //状态    2-等待审核(初始化)  1-审核通过  0-审核中  -1-审核退回
            Integer state = 1;

            if (soData.getInsertType() == -2) {
                //草稿
                state = 1;
            } else if (soData.getInsertType() == 0) {
                //正式提交
                String billNo1 = soData.getSoMaster().getBillNo();
                //通过草稿提交，则需要先把草稿删掉
                if (billNo1 != null) {
                    soMasterService.deleteByBillNo(billNo1);
                }
                /**
                 * 添加审核流
                 */
                //        -1不通过  0-流转中 1-已通过
                state = caseMasterService.createCase(billNo, 3, currentUser.getUserId(), soMaster.getWareId(), soMaster.getOrganizationId());
            }

            soMaster.setCreateUserId(createUserId);
            soMaster.setCreateUserName(createUserName);
            soMaster.setCreateTime(createTime);
            soMaster.setBillNo(billNo);
            soMaster.setCaseState(state);
            soMaster.setInsertType(soData.getInsertType());
            soMaster.setBillSource(soData.getBillSource());
            soMaster.setSoStructure(soData.getSoDetails().size());
            soMasterService.save(soMaster);


            List<SoDetail> soDetails = soData.getSoDetails();
            for (int i = 0; i < soDetails.size(); i++) {
                String detailNo = billNo + "-" + (i + 1);
                SoDetail soDetail = soDetails.get(i);
                soDetail.setBillNo(billNo);
                soDetail.setSoMasterId(soMaster.getSoMasterId());
                soDetail.setDetailNo(detailNo);
                soDetail.setState(0);
                soDetailService.save(soDetail);
            }
        }
    }

    @Override
    public void createFile(String billNo, CurrentUser currentUser) {
        SoMaster soMaster = this.findBy("bill_no", billNo);
        //状态为 ASN完成状态
        Integer fileUserId = currentUser.getUserId();
        String fileUserName = currentUser.getUserName();
        String fileTime = DateUtils.getNowDateTimeString();
        if (soMaster.getState() != 10) {
            throw new ServiceException(CommonCode.SO_FILE_ERROR);
        }
        BillRecord billRecord = new BillRecord();
        billRecord.setBillNo(billNo);
        billRecord.setRecordType(26);//SO归档
        billRecord.setCreateTime(fileTime);
        billRecord.setCreateUserId(fileUserId);
        billRecord.setCreateUserName(fileUserName);
        billRecordService.createBillRecord(billRecord, currentUser);

        SoMasterFile soMasterFile = new SoMasterFile();
        BeanUtils.copyProperties(soMaster, soMasterFile);

        soMasterFile.setFileUserId(fileUserId);
        soMasterFile.setFileUserName(fileUserName);
        soMasterFile.setFileTime(fileTime);
        soMasterFileService.save(soMasterFile);

        List<SoDetail> soDetails = soDetailService.findByBillNo(billNo);

        for (int i = 0; i < soDetails.size(); i++) {

            SoDetail soDetail = soDetails.get(i);
            SoDetailFile soDetailFile = new SoDetailFile();
            BeanUtils.copyProperties(soDetail, soDetailFile);

            soDetailFileService.save(soDetailFile);


        }
        soMasterService.deleteByBillNo(billNo);
        BillRecord billRecord1 = billRecordService.findByBillNoAndType(billNo, 26);//SO归档
        billRecord1.setModifyUserId(fileUserId);
        billRecord1.setModifyUserName(fileUserName);
        billRecord1.setModifyTime(DateUtils.getNowDateTimeString());
        billRecordService.updateById(billRecord1);
    }

    @Override
    public SoMaster findBy(String fileName, String value) {
        QueryWrapper<SoMaster> qw = new QueryWrapper<>();
        return this.getOne(qw.eq(fileName, value));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendOut(SoMaster soMaster, CurrentUser currentUser) {
        //Step1.找到SO对应的出库单
        QueryWrapper<OutMaster> qw = new QueryWrapper<>();
        qw.eq("so_master_id", soMaster.getSoMasterId());
        qw.eq("state", WareTaskConstant.OUT_STATE_INIT);
        OutMaster outMaster = outMasterService.getOne(qw);
        if (ObjectUtil.isNull(outMaster)) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "不存在待发库存");
        }

        //Step2.出库单确认
        outMasterService.confirmOutBill(outMaster, currentUser);

        //Step3.调用接口
//        Integer erpAreaId = cellInfoService.findbyCellCode(cellCode);
//        BaseAssist baseAssist = new BaseAssist();
//        baseAssist.setStockId2(erpAreaId);
//        extracted(soMaster, pickTasks);
    }

    private void updateSoState(SoMaster soMaster) {
        List<SoDetail> soDetails = soDetailService.getListByField("bill_no", soMaster.getBillNo());

        boolean flag = true;
        for (SoDetail soDetail : soDetails) {
            if (soDetail.getOrderQuantity().equals(soDetail.getDeliveryQuantity())) {
                soDetail.setState(WareTaskConstant.OUT_STATE_CLOSE);
                soDetailService.updateById(soDetail);
            }else {
                flag = false;
            }
        }

        if (flag) {
            soMaster.setState(WareTaskConstant.OUT_STATE_CLOSE);
            soMasterService.updateById(soMaster);
        }
    }

    private void extracted(SoMaster soMaster, List<PickTask> pickTaskList) {
        //erp回传
        //2003 采购退货 2004 销售出货 2005 生产领料 2006 调拨出库
        //出库
        Integer asnType = soMaster.getSoType();
        pickTaskList.stream().forEach(task -> {
            SoDetail detail = soDetailMapper.selectById(task.getSoDetailId());
            detail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
            soDetailMapper.updateById(detail);
            Double pickQuantity = task.getPickQuantity();
            if (asnType.intValue() == 2003) {//2003 采购退货
                List<PurchaseReturnVo> purchaseReturnVos = new ArrayList<>();
                PurchaseReturnVo purchaseReturnVo = new PurchaseReturnVo();
                purchaseReturnVo.setRtnNo(detail.getBillNo());//退货申请单号
                purchaseReturnVo.setRtnLineNo(detail.getErpLineNo());//退货申请单行号
//                purchaseReturnVo.setRejectQty(detail.getQtyTrans());//退货数量
//                purchaseReturnVo.setDeductQty(detail.getQtyArTrans());//退扣数量
//                purchaseReturnVo.setFillQty(detail.getQtyOrderTrans());//退补数量
                purchaseReturnVo.setRejectQty(pickQuantity);//退货数量
                purchaseReturnVo.setDeductQty(0d);//退扣数量
                purchaseReturnVo.setFillQty(0d);//退补数量
                purchaseReturnVo.setWhCode(detail.getWareCode());//存储地点(默认原存储地点)
                purchaseReturnVos.add(purchaseReturnVo);
                Map<String, Object> soMap = new HashMap<>();
                try {
                    soMap = doPostOrGet("http://61.160.125.186:5555/zp/api/ZpViewRtn/Create", JSONObject.toJSONString(purchaseReturnVos));
                    if (soMap.get("code") == null || !"200".equals(soMap.get("code").toString())) {
                        throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "采购退货回传失败，具体原因:" + soMap.get("msg") + toString());
                    }
                } finally {
                    soMasterServiceImpl.erpLog(soMap, asnType.intValue());
                }
            } else if (asnType.intValue() == 2004) {//2004 销售出货
                List<SalesShipmentVo> salesShipmentVos = new ArrayList<SalesShipmentVo>();
                SalesShipmentVo salesShipmentVo = new SalesShipmentVo();
                salesShipmentVo.setShipPlanNo(detail.getBillNo());//出货计划单号
                salesShipmentVo.setShipPlanLineNo(detail.getErpLineNo());//出货计划单行号
                salesShipmentVo.setShipQty(detail.getPickQuantity());//出货数量
                String areaCode = task.getAreaCode();
                salesShipmentVo.setWhCode(areaCode);//存储地点
                salesShipmentVos.add(salesShipmentVo);
                Map<String, Object> soMap = new HashMap<>();
                try {
                    soMap = doPostOrGet("http://61.160.125.186:5555/zp/api/ZpViewShipPlan/Create", JSONObject.toJSONString(salesShipmentVos));
                    if (soMap.get("code") == null || !"200".equals(soMap.get("code").toString())) {
                        throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "销售回传失败,具体原因:" + soMap.get("msg").toString());
                    }
                } finally {
                    soMasterServiceImpl.erpLog(soMap, asnType.intValue());
                }
            } else if (asnType.intValue() == 2005) {//2005 生产领料
                List<ProductionPicking> productionPickings = new ArrayList<>();
                ProductionPicking productionPicking = new ProductionPicking();
                productionPicking.setMo(detail.getMo());//生产订单ID
                productionPicking.setMoPick(Long.parseLong(detail.getMoPick()));//生产订单备料ID
                productionPicking.setIssueQty(detail.getPickQuantity());//应发数量
                String areaCode = task.getAreaCode();
                productionPicking.setWhCode(areaCode);//存储地点编码
                productionPickings.add(productionPicking);
                Map<String, Object> soMap = new HashMap<>();
                try {
                    soMap = doPostOrGet("http://61.160.125.186:5555/zp/api/ZpViewPick/Create", JSONObject.toJSONString(productionPickings));
                    if (soMap.get("code") == null || !"200".equals(soMap.get("code").toString())) {
                        throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "生产领料回传失败,具体原因：" + soMap.get("msg").toString());
                    }
                } finally {
                    soMasterServiceImpl.erpLog(soMap, asnType.intValue());
                }
            } else if (asnType.intValue() == 2006) {//2006 调拨出库
                List<AllocatingOutboundVo> allocatingOutboundVos = new ArrayList<AllocatingOutboundVo>();
                AllocatingOutboundVo allocatingOutboundVo = new AllocatingOutboundVo();
                allocatingOutboundVo.setDocType("TransOut002");
                allocatingOutboundVo.setTransferType(1);
                List<LinesVo> linesVos = new ArrayList<>();
                LinesVo linesVo = new LinesVo();
                linesVo.setItemCode(detail.getItemCode());//料品编码
                linesVo.setOutWhCode(task.getAreaCode());//调出存储地点编码
                linesVo.setInWhCode(soMaster.getSoUdfHs1());//调入存储地点编码(委外存储地点编码)
                linesVo.setStoreQty(detail.getPickQuantity());//调拨数量
                linesVos.add(linesVo);
                allocatingOutboundVo.setLines(linesVos);
                allocatingOutboundVos.add(allocatingOutboundVo);
                Map<String, Object> soMap = new HashMap<>();
                try {
                    soMap = doPostOrGet("http://61.160.125.186:5555/zp/api/ZpViewTransOut/Create", JSONObject.toJSONString(allocatingOutboundVos));
                    if (soMap.get("code") == null || !"200".equals(soMap.get("code").toString())) {
                        throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "调拨出库回传失败，具体原因:" + soMap.get("msg").toString());
                    }
                } finally {
                    soMasterServiceImpl.erpLog(soMap, asnType.intValue());
                }
            }
        });
    }

    /**
     * 添加回传日志信息
     *
     * @param returnMap
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void erpLog(Map<String, Object> returnMap, int type) {
        //添加回传日志信息
        ErpBackRecord erpBackRecord = new ErpBackRecord();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String tim = df.format(new Date());
        erpBackRecord.setCreateTime(tim);
        erpBackRecord.setParam(returnMap.get("result").toString());
        erpBackRecord.setMsg(returnMap.get("msg").toString());
        erpBackRecord.setCode(returnMap.get("code").toString());
        erpBackRecord.setType(type+"" );
        int insert = erpBackRecordMapper.insert(erpBackRecord);
        if (insert <= 0) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "添加日志失败");
        }
    }

    /**
     * 调用地第三方接口
     *
     * @param pathUrl 地址
     * @param data    参数
     * @return
     */
    public static Map<String, Object> doPostOrGet(String pathUrl, String data) {
        System.out.println("================================================");
        System.out.println(data);
        System.out.println("================================================");
        OutputStreamWriter out = null;
        BufferedReader br = null;
        String result = "";
        Map<String, Object> map = new HashMap<>();
        try {
            URL url = new URL(pathUrl);
            //打开和url之间的连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //请求方式
            conn.setRequestMethod("POST");
            //conn.setRequestMethod("GET");

            //设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");

            //DoOutput设置是否向httpUrlConnection输出，DoInput设置是否从httpUrlConnection读入，此外发送post请求必须设置这两个
            conn.setDoOutput(true);
            conn.setDoInput(true);

            /**
             * 下面的三句代码，就是调用第三方http接口
             */
            //获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            //发送请求参数即数据
            out.write(data);
            //flush输出流的缓冲
            out.flush();

            /**
             * 下面的代码相当于，获取调用第三方http接口后返回的结果
             */
            //获取URLConnection对象对应的输入流
            InputStream is = conn.getInputStream();
            //构造一个字符流缓存
            br = new BufferedReader(new InputStreamReader(is));
            String str = "";
            while ((str = br.readLine()) != null) {
                result += str;
            }
            map = JSON.parseObject(result);
            System.out.println(result);
            //关闭流
            is.close();
            //断开连接，disconnect是在底层tcp socket链接空闲时才切断，如果正在被其他线程使用就不切断。
            conn.disconnect();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    @Autowired
    private StrategyErpService strategyErpService;
    @Autowired
    private WareInfoMapper wareInfoMapper;


    public void allot(String pickIds, String cellCode) {
        List<String> pickId = Arrays.asList(pickIds.split(","));
        List<PickTask> pickTasks = pickTaskService.listByIds(pickId);
        Set<Integer> integers = pickTasks.stream().map(PickTask::getInventoryId).collect(Collectors.toSet());
        List<Inventory> inventories = inventoryService.listByIds(integers);
        double sum = inventories.stream().mapToDouble(item -> item.getQuantity() - item.getAllotQuantity()).sum();
        Inventory oldInventory = inventories.iterator().next();
        Inventory inventory = new Inventory();
        BeanUtils.copyProperties(oldInventory, inventory);
        Integer erpAreaId = cellInfoService.findbyCellCode(cellCode);
        oldInventory.setAllotQuantity(0.00);
        inventory.setInventoryId(null);
        inventory.setBoxCode(codeRuleService.generateCodeByRedis("CT"));
        inventory.setErpAreaId(erpAreaId);
        inventory.setQuantity(sum);
        inventory.setCellCode(cellCode);
        inventoryService.save(inventory);
    }




    @Override
    public List<SoMaster> findSoGroupInfo(SoMasterCriteria criteria) {
        return soMasterMapper.findSoGroupInfo(criteria);
    }

    @Override
    public List<SoMaster> findSoByWave(SoMasterCriteria criteria) {
        return soMasterMapper.findSoByWave(criteria);
    }

    @Override
    public Integer findCountByWaveIdAndState(Integer waveMasterId, Integer state) {
        return soMasterMapper.findCountByWaveIdAndState(waveMasterId, state);
    }


    @Override
    public List<SoMaster> findCanTongBu() {
        return soMasterMapper.findCanTongBu();
    }

    @Override
//    public void setCarriersWithRouteTactic(Integer organizationId, Integer wareId) {
    public void setCarriersWithRouteTactic() {
        SoMasterCriteria soMasterCriteria = new SoMasterCriteria();
//        soMasterCriteria.setOrganizationId(organizationId);
//        soMasterCriteria.setWareId(wareId);
        List<SoMasterDto> soMasters = soMasterMapper.findThatNoCarrier(soMasterCriteria);
        RouteTacticCriteria criteria = new RouteTacticCriteria();
//        criteria.setOrganizationId(organizationId);
//        criteria.setWareId(wareId);
        criteria.setState(1);
        List<RouteTactic> routeTactics = routeTacticService.findList(criteria);
        if (routeTactics.size() == 0) {
            throw new ServiceException(CommonCode.NO_ROUTE_TACTIC);
        }

        for (SoMasterDto soMaster : soMasters) {
            Double weight = soMaster.getWeight();
            Double size = soMaster.getSize();
            tacticLoop:
            for (RouteTactic routeTactic : routeTactics) {
                Double maxWeight = routeTactic.getMaxWeight();
                Double minWeight = routeTactic.getMinWeight();
                Double maxSize = routeTactic.getMaxSize();
                Double minSize = routeTactic.getMinSize();
                if (weight > minWeight && weight < maxWeight && size > minSize && size < maxSize) {
                    soMaster.setCarrierId(routeTactic.getCarrierId());
                    soMaster.setCarrierName(routeTactic.getCarrierName());
                    soMasterService.updateById(soMaster);
                    break tacticLoop;
                }
            }
        }
    }

    @Override
    public List<PdaSearchSoData> pdaSearchSo(String trackCode) {
        return soMasterMapper.pdaSearchSo(trackCode);
    }

    @Override
    public SoMasterYdyp getYdyp(String itemCode, Integer wareId, Integer waveId) {
        return soMasterMapper.getYdyp(itemCode, wareId, waveId);
    }

    @Override
    public SoMasterYdyp getYdyp2(String itemCode, Integer wareId, Integer waveId) {
        return soMasterMapper.getYdyp2(itemCode, wareId, waveId);
    }


    @Autowired
    private WareInfoService wareInfoService;
    @Autowired
    private ItemInfoService itemInfoService;
    @Autowired
    private OrganizationService organizationService;

    @Override
    public void createSO(CreateSo createSo, CurrentUser currentUser) {
        SoMaster soMaster = soMaster = this.findBy("bill_no", createSo.getBillNo());
        if (soMaster != null) {
            throw new ServiceException(CommonCode.BILL_NO, "");
        }
        soMaster = new SoMaster();
        if (createSo.getWareCode() == null) {
            throw new ServiceException(CommonCode.WARE_NULL, "");
        }
        if (createSo.getOrgCode() == null) {
            throw new ServiceException(CommonCode.ORG_NULL, "");
        }

        String billNo = createSo.getBillNo();
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();
        String wareCode = createSo.getWareCode();
        String orgCode = createSo.getOrgCode();
        WareInfo wareInfo = wareInfoService.getOneByField("ware_code", wareCode);
        Organization organization = organizationService.findBy("organizationCode", orgCode);

        if (createSo.getOrderTime() == null || createSo.getOrderTime().equals("")) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "下单时间不得为空");
        }

        if (wareInfo == null) {
            throw new ServiceException(CommonCode.WARE_NULL, "");
        }
        if (organization == null) {
            throw new ServiceException(CommonCode.ORG_NULL, "");
        }
        Integer state = 2;
        // state = caseMasterService.createCase(billNo, 2, currentUser.getUserId(), wareInfo.getWareId(),organization.getOrganizationId());

        soMaster.setState(state);
        soMaster.setBillNo(billNo);
        soMaster.setCreateTime(createTime);
        soMaster.setCreateUserId(createUserId);
        soMaster.setCreateUserName(createUserName);
        soMaster.setWareId(wareInfo.getWareId());
        soMaster.setWareName(wareInfo.getWareName());
        soMaster.setWareId(wareInfo.getWareId());
        soMaster.setWareCode(wareInfo.getWareCode());
        soMaster.setOrganizationCode(organization.getOrganizationCode());
        soMaster.setOrganizationName(organization.getOrganizationName());
        soMaster.setOrganizationId(organization.getOrganizationId());
        soMaster.setAllotBillNo(createSo.getBillNo());
        soMaster.setShipCode(createSo.getShipCode());
        soMaster.setShipBillCode(createSo.getShipBillCode());
        soMaster.setExpressBillUrl(createSo.getExpressBillUrl());
        soMaster.setInsertType(4);
        soMaster.setOrderTime(createSo.getOrderTime());

        CreateSoShippingAddress shippingAddress = createSo.getShippingAddress();
        soMaster.setShipLinkMan(shippingAddress.getLinkMan());
        soMaster.setShipLinkPhone(shippingAddress.getLinkPhone());
        soMaster.setShipCity(shippingAddress.getCity());
        soMaster.setShipCountry(shippingAddress.getCountry());
        soMaster.setShipProvince(shippingAddress.getProvince());
        soMaster.setShipArea(shippingAddress.getArea());
        soMaster.setShipDetailAddress(shippingAddress.getDetailAddress());

        CreateSoDeliveryAddress deliveryAddress = createSo.getDeliveryAddress();
        soMaster.setLinkMan(deliveryAddress.getLinkMan());
        soMaster.setLinkPhone(deliveryAddress.getLinkPhone());
        soMaster.setProvince(deliveryAddress.getProvince());
        soMaster.setCity(deliveryAddress.getCity());
        soMaster.setCountry(deliveryAddress.getCountry());
        soMaster.setArea(deliveryAddress.getArea());
        soMaster.setDetailAddress(deliveryAddress.getDetailAddress());
        soMaster.setCountry(deliveryAddress.getCountry());


        soMaster.setLastMileDestination(createSo.getLastMileDestination());
        soMaster.setLastMileLineCode(createSo.getLastMileLineCode());
        soMaster.setLastMileSortingCode(createSo.getLastMileSortingCode());
        soMaster.setSoUdfHs1(createSo.getExt1());
        soMaster.setSoUdfHs2(createSo.getExt2());
        soMaster.setSoUdfHs3(createSo.getExt3());
        soMaster.setSoStructure(createSo.getSoSkuDetails().size());
        soMaster.setTotalPrice(createSo.getCodValue());
        soMaster.setTradeNo(createSo.getTradeNo());
        soMaster.setShop(createSo.getShop());
        soMasterService.save(soMaster);


        List<CreateSoSkuDetail> asnskuDetails = createSo.getSoSkuDetails();
        for (int i = 0; i < asnskuDetails.size(); i++) {
            CreateSoSkuDetail createSoSkuDetail = asnskuDetails.get(i);

            SoDetail soDetail = new SoDetail();
            soDetail.setBillNo(soMaster.getBillNo());
            soDetail.setDetailNo(soMaster.getBillNo() + (i + 1));
            soDetail.setItemCode(createSoSkuDetail.getSkuCode());

            if (createSoSkuDetail.getSkuCode() == null || createSoSkuDetail.getSkuCode().trim().equals("")) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "SKU无效");
            }
            ItemInfo itemInfo = itemInfoService.findBy("item_code", createSoSkuDetail.getSkuCode());
            if (itemInfo == null) {
                itemInfo = new ItemInfo();
                itemInfo.setImgUrl(createSoSkuDetail.getImgUrl());
                itemInfo.setItemCode(createSoSkuDetail.getSkuCode());
                itemInfo.setItemName(createSoSkuDetail.getSkuName());
                itemInfo.setPackCode("sys_pack");
                itemInfoService.save(itemInfo);
            }
            soDetail.setItemName(itemInfo.getItemName());
            soDetail.setSpec(itemInfo.getSpec());
            soDetail.setModel(itemInfo.getModel());
            soDetail.setImgUrl(itemInfo.getImgUrl());
            soDetail.setPackDetailId(166);
            soDetail.setTransRatio(1.0);
            soDetail.setPackDescribe("each");
            soDetail.setOrderQuantity(createSoSkuDetail.getQuantity());
            soDetailService.save(soDetail);
        }
    }

    @Override
    public Integer getMaxPriority() {
        return soMasterMapper.getMaxPriority();
    }

    @Override
    public void updatePriority(Integer soMasterId, Integer priority) {
        soMasterMapper.updatePriority(soMasterId, priority);
    }


    //去重出库表
    public List<BillOutBO> filterBillOut(List<BillOutBO> billOutBOS, Set<String> billNo, List<Integer> notBillNums) {

        //不包含的单据类型

        return billOutBOS.stream().filter(item -> !billNo.contains(item.getBillNo())
                && !notBillNums.contains(item.getBillTypeId())

        ).collect(Collectors.toList());
    }


    //去重出库详情表
    public List<PurchaseOrderDetailBO> filterDetaiBo(List<PurchaseOrderDetailBO> billOutDetailBOS, Set<String> billNo, List<Integer> notBillNums) {
        return billOutDetailBOS.stream().filter(item -> !billNo.contains(item.getBillNo()) && !notBillNums.contains(item.getBillType())).collect(Collectors.toList());
    }

    public List<PurchaseOrderDetailBO> insertBillNo(PurchaseOrderBO billOutBO) {
        List<PurchaseOrderDetailBO> billOutDetail = billOutBO.getDetails();
        return billOutDetail.stream().map(
                item -> {
                    item.setSupplierName(billOutBO.getSupplierName());
                    item.setBillNo(billOutBO.getBillNo());
                    item.setOrderBillNo(billOutBO.getOrderBillNo());
                    item.setSourceBillId(billOutBO.getId());
                    item.setBillType(billOutBO.getBillTypeId());

                    return item;
                }
        ).collect(Collectors.toList());
    }

//
//    public List<BillOutDetailBO> getAllBillOut(List<BillOutDetailBO> list) {
//
//    }

    public Double sumSoQty(List<BillOutDetailBO> list, String billNo) {
        return list.stream().filter(item -> item.getBillNo().equals(billNo)).mapToDouble(BillOutDetailBO::getQty).sum();
    }

    public Double sumQcQty(List<BillOutDetailBO> list, String billNo) {
        return list.stream().filter(item -> item.getBillNo().equals(billNo)).mapToDouble(BillOutDetailBO::getQcQty).sum();
    }

    @Override
    public String saveBillOutInfo(String date) {
        return null;
    }


    //红蓝字对冲
    public List<PurchaseOrderDetailBO> merge(Map<String, List<PurchaseOrderDetailBO>> soDetailMap) {
        List<PurchaseOrderDetailBO> billOutDetailBOList = new ArrayList<>();
        soDetailMap.forEach((key, val) -> {
            //过滤一遍蓝字标准件                                    红蓝字为ture
            List<PurchaseOrderDetailBO> collect = val.stream().filter(PurchaseOrderDetailBO::getTargetBillROB).collect(Collectors.toList());
            //遍历详情数据
            for (PurchaseOrderDetailBO billOutDetailBO : collect) {
                //过滤跟根据物料编码遍历红字
                List<PurchaseOrderDetailBO> billOutDetailFalse = val.stream().filter(item -> !item.getTargetBillROB()
                        && item.getItemNumber().equals(billOutDetailBO.getItemNumber())
                        && ObjectUtil.isNotEmpty(item)).collect(Collectors.toList());
                //for循环红字
                for (PurchaseOrderDetailBO outDetailBO : billOutDetailFalse) {
                    //如果篮字数量大于红字数量
                    if (billOutDetailBO.getQty() - outDetailBO.getQty() >= 0) {
                        //修改对冲修改红字数量
                        billOutDetailBO.setQty((billOutDetailBO.getQty() - outDetailBO.getQty()));
                        outDetailBO.setQty(0.00);
                        //重写hashCode 根据id删除
//                        billOutDetailFalse.remove(outDetailBO);
                        val.remove(outDetailBO);
                    } else if (billOutDetailBO.getQty() < outDetailBO.getQcQty()) {
                        //不足待分配
                        billOutDetailBO.setQty(outDetailBO.getQcQty() - billOutDetailBO.getQty());
                        //数量制空抵消
                        outDetailBO.setQty(outDetailBO.getQcQty() - outDetailBO.getQcQty() - billOutDetailBO.getQty());
                    }
                }
                billOutDetailBOList.add(billOutDetailBO);
            }
        });
        return billOutDetailBOList.stream().filter(item -> item.getQty() != 0).collect(Collectors.toList());
    }


//

    @Override
    public void createSoMaster2(SoData soData, CurrentUser currentUser) {
        /**
         *  新建SO单据
         */
        SoMaster soMaster = soData.getSoMaster();
        String tableName = "so_master";
        Integer nextId = validatorService.getNextId(tableName);

        String billNo = "SO" + "-" + nextId;
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();

        if (soData.getBillSource() == 1 || soData.getBillSource() == 3 || soData.getBillSource() == 4) {
            //状态    2-等待审核(初始化)  1-审核通过  0-审核中  -1-审核退回
            Integer state = 1;

            if (soData.getInsertType() == -2) {
                //草稿
                state = 1;
            } else if (soData.getInsertType() == 0) {
                //正式提交
                String billNo1 = soData.getSoMaster().getBillNo();
                //通过草稿提交，则需要先把草稿删掉
                if (billNo1 != null) {
                    soMasterService.deleteByBillNo(billNo1);
                }
                /**
                 * 添加审核流
                 */
                //        -1不通过  0-流转中 1-已通过
                state = caseMasterService.createCase(billNo, 3, currentUser.getUserId(), soMaster.getWareId(), soMaster.getOrganizationId());
            }

            soMaster.setCreateUserId(createUserId);
            soMaster.setCreateUserName(createUserName);
            soMaster.setCreateTime(createTime);
            soMaster.setBillNo(billNo);
            soMaster.setCaseState(state);
            soMaster.setInsertType(soData.getInsertType());
            soMaster.setBillSource(soData.getBillSource());
            soMaster.setSoStructure(soData.getSoDetails().size());
            soMaster.setSoUdfHs1("1");//标记先发配件出库单据
            soMasterService.save(soMaster);


            List<SoDetail> soDetails = soData.getSoDetails();
            for (int i = 0; i < soDetails.size(); i++) {
                String detailNo = billNo + "-" + (i + 1);
                SoDetail soDetail = soDetails.get(i);
                soDetail.setBillNo(billNo);
                soDetail.setDetailNo(detailNo);
                soDetail.setState(0);
                soDetailService.save(soDetail);
            }
        }
    }

    @Override
    public List<SoMasterDto> findList2(SoMasterCriteria criteria) {
        return soMasterMapper.findList2(criteria);
    }

    @Override
    public void createSoMaster3(SoData soData, CurrentUser currentUser) {
        /**
         *  新建SO单据
         */
        SoMaster soMaster = soData.getSoMaster();
        String tableName = "so_master";
        Integer nextId = validatorService.getNextId(tableName);

        String billNo = "SO" + "-" + nextId;
        Integer createUserId = currentUser.getUserId();
        String createUserName = currentUser.getUserName();
        String createTime = DateUtils.getNowDateTimeString();

        if (soData.getBillSource() == 1 || soData.getBillSource() == 3 || soData.getBillSource() == 4) {
            //状态    2-等待审核(初始化)  1-审核通过  0-审核中  -1-审核退回
            Integer state = 1;

            if (soData.getInsertType() == -2) {
                //草稿
                state = 1;
            } else if (soData.getInsertType() == 0) {
                //正式提交
                String billNo1 = soData.getSoMaster().getBillNo();
                //通过草稿提交，则需要先把草稿删掉
                if (billNo1 != null) {
                    soMasterService.deleteByBillNo(billNo1);
                }
                /**
                 * 添加审核流
                 */
                //        -1不通过  0-流转中 1-已通过
                state = caseMasterService.createCase(billNo, 3, currentUser.getUserId(), soMaster.getWareId(), soMaster.getOrganizationId());
            }

            soMaster.setCreateUserId(createUserId);
            soMaster.setCreateUserName(createUserName);
            soMaster.setCreateTime(createTime);
            soMaster.setBillNo(billNo);
            soMaster.setCaseState(state);
            soMaster.setInsertType(soData.getInsertType());
            soMaster.setBillSource(soData.getBillSource());
            soMaster.setSoStructure(soData.getSoDetails().size());
            soMaster.setSoUdfHs1("2");//标记先发配件出库单据
            soMasterService.save(soMaster);


            List<SoDetail> soDetails = soData.getSoDetails();
            for (int i = 0; i < soDetails.size(); i++) {
                String detailNo = billNo + "-" + (i + 1);
                SoDetail soDetail = soDetails.get(i);
                soDetail.setBillNo(billNo);
                soDetail.setDetailNo(detailNo);
                soDetail.setState(0);
                soDetailService.save(soDetail);
            }
        }
    }

    @Override
    public List<SoMasterDto> findList3(SoMasterCriteria criteria) {
        return soMasterMapper.findList3(criteria);
    }

    /**
     * 获取任务数据
     *
     * @param
     * @return
     */
    @Override
    public List<SoMasterVo> alignList(QueryCriteria criteria) {
        return baseMapper.alignList(criteria);
    }

    /**
     * 齐套提交
     *
     * @param soDetailVo
     */
    @Override
    public void submitQitao(SoDetailVo soDetailVo) {
//
//        //借料项
//        List<BillOutDetailBO> billOutDetailBOS = soDetailVo.getBillOutDetailBOS().stream().filter(item -> ObjectUtil.isNotEmpty(item.getNumber())).collect(Collectors.toList());
//        //借料项全部数
//        double sum = billOutDetailBOS.stream().mapToDouble(BillOutDetailBO::getNumber).sum();
//        if (sum == 0) {
//            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "借料数量为空");
//        }
//        //全部项
//        SoDetail soDetail = soDetailVo.getAll().get(0);
//        Map<String, Object> soDetil = baseMapper.findByDetilId(soDetail.getSoDetailId());
//        Inventory inventory = new Inventory();
//        //todo 转换入库,
//        this.copyInventory(inventory, soDetil);
//        inventory.setQuantity(sum);
//        inventoryService.save(inventory);
//        //todo 判断改订单号是否库存足够
//        if (this.isQitao(soDetail.getBillNo())) {
//            //修改状态为已齐套
//            SoMaster soMaster = soMasterService.getOne(new QueryWrapper<SoMaster>().eq("bill_no", soDetail.getBillNo()));
//            soMaster.setIsVerify(1);
//            soMasterService.updateById(soMaster);
//        }
//        //
//        if (soDetail.getOrderQuantity() - soDetail.getPickQuantity() < sum) {
//            throw new ServiceException(CommonCode.PARAMETER_ERROR, "借料数量大于差异数量");
//        }
//        //回传ERP
//        OrderToErpBO orderToErpBO = pushErpBean(billOutDetailBOS);
//        pushErpService.pushIMBIll(orderToErpBO);
    }


//    public OrderToErpBO pushErpBean(List<BillOutDetailBO> detailBOS) {
//        OrderToErpBO orderToErpBO = new OrderToErpBO();
//        orderToErpBO.setBillTypeId(29);
//        orderToErpBO.setRob(true);
//        orderToErpBO.setBillNo("12456");
//        orderToErpBO.setSourceBillTypeId(251300022);
////        orderToErpBO.setStockId(45795);
////        orderToErpBO.setCategoryId2(950901);
////        orderToErpBO.setCategoryId3(0);
//
//        List<OrderDetailBO> details = new ArrayList<>();
//
//        detailBOS.forEach(item -> {
//            OrderDetailBO orderDetailBO = new OrderDetailBO();
//            orderDetailBO.setSourceBillId(item.getId());//源单据id
//            orderDetailBO.setSourceBillDetailRowIndex(item.getRowIndex());//行号
//            orderDetailBO.setAuxPropId(item.getAuxPropId());//辅助类型id
//            orderDetailBO.setBatchNo(item.getBatchNo()); //批次
//            orderDetailBO.setQty(item.getNumber());//数量
////            orderDetailBO.setShelfLifeDays(100);//天数
//            orderDetailBO.setBatchNo(item.getBatchNo()); //计划跟踪号
////            orderDetailBO.setStockPlaceId(1);
//            orderDetailBO.setStockId(495);
//            orderDetailBO.setStockId2(505);
//            details.add(orderDetailBO);
//        });
//        orderToErpBO.setDetails(details);
//        return orderToErpBO;
//    }

//    public boolean isQitao(String billNo) {
//        List<SoDetail> soDetailList = soDetailService.list(new QueryWrapper<SoDetail>().in("bill_no", billNo));
//        Set<String> itemCodeSet = soDetailList.stream().map(SoDetail::getItemCode).collect(Collectors.toSet());
//        List<Inventory> inventoryList = inventoryService.list(new QueryWrapper<Inventory>().in("item_code", itemCodeSet));
//        for (SoDetail soDetail : soDetailList) {
//            // //货主id 88货主Id默认为 -1 自有, code SYS_MINE
//            soDetail.setMarginQty(soDetailService.putNumber(inventoryList, soDetail.getItemCode(), -1));
//        }
//        List<SoDetail> soDetails = soDetailService.lendDetail(soDetailList);
//        return soDetails.size() == soDetailList.size();
//    }
//
//    public void copyInventory(Inventory inventory, Map<String, Object> map) {
//        inventory.setWareId(Integer.valueOf(map.get("wareId").toString()));
//        inventory.setWareName(map.get("wareName").toString());
//        inventory.setOrganizationId(Integer.valueOf(map.get("organizationId").toString()));
//        inventory.setOrganizationName(map.get("organizationName").toString());
//        inventory.setItemCode(map.get("itemCode").toString());
//        inventory.setItemName(map.get("itemName").toString());
//        inventory.setBillNo(map.get("billNo").toString());
//    }


    @Override
    @Transactional
    public void TjRgOutRecord(RgProdOutRecord rgProdOutRecord, String userName) {
        // 修改状态为出库
        rgProdOutRecord.setStatus(4000);
        rgProdOutRecordService.saveOrUpdate(rgProdOutRecord);
        // 回传给erp
        // 封装数据
        // 修改状态为出库
        SDPackingBo sdPackingBo = new SDPackingBo();
        sdPackingBo.setAgreementNo(rgProdOutRecord.getAgreementNo());
        sdPackingBo.setPackingNo(rgProdOutRecord.getPackingNo());
        // 0=计划； 1000=生产； 2000=检验； 4000=出库； -1=作废
        sdPackingBo.setStatus(4000);
        sdPackingBo.setUserName(userName);
        // 回传ERP
        pushErpService.sDPacking(sdPackingBo);
    }

    /**
     * 根据生产任务判断是否需要齐套
     *
     * @param yieldBill
     * @return
     */
    @Override
    public Boolean dispatch(String yieldBill) {
        Map<String, Double> map = baseMapper.dispatch(yieldBill);
        return ObjectUtil.isEmpty(map) || map.get("deliveryQuantity") >= map.get("orderQuantity");
    }

    @Autowired
    private ErpService erpService;

    /**
     * 采购退货通知单查询接口
     *
     * @param hashMap 条件
     */
    @Override
    public void addPurchaseReturn(Map<String, Object> hashMap) {
        hashMap.put("status", 5);
        hashMap.put("makeDate", ErpInConstant.SYNC_DATA);
        hashMap.put("docType", "RCV21");
        //获取采购退货通知单接口
        List<ErpOutTask> returnGoods = erpService.purchaseReturnNotice(hashMap);
//        System.out.println(returnGoods.size());
        this.saveBathErpForZP(returnGoods, ErpOutConstant.ERP_OUT_TYPE_ASNRET);

    }

    /**
     * 销售出库查询接口
     *
     * @param hashMap 条件
     */
    @Override
    public void addSalesOutbound(Map<String, Object> hashMap) {
        hashMap.put("makeDate", ErpInConstant.SYNC_DATA);
        hashMap.put("status", "3");
        //查询销售出库查询接口
        List<ErpOutTask> returnGoods = erpService.salesShipmentQuery(hashMap);
//        System.out.println(returnGoods.size());
        this.saveBathErpForZP(returnGoods, ErpOutConstant.ERP_OUT_TYPE_SALES);
    }


    /**
     * 杂发查询接口
     *
     * @param hashMap 条件
     */
    @Override
    public void addProductionPicking(Map<String, Object> hashMap) {
        hashMap.put("makeDate",DateUtil.today());//生产领料
//        hashMap.put("makeDate","2022-11-11");//生产领料
        hashMap.put("status",2);
        //获取生产领料申请单查询接口
        List<ErpOutTask> returnGoods = erpService.productionOfPickingApplication(hashMap);
//        System.out.println(returnGoods.size());
        this.saveBathErpForZP(returnGoods, ErpOutConstant.ERP_OUT_TYPE_ZF);
    }


    /**
     * 卓品
     * 处理从接口同步过来的ERP任务，新增或者修改
     * @param erpTaskList 处理从接口同步过来的ERP任务
     */
    public void saveBathErpForZP(List<ErpOutTask> erpTaskList, Integer billType) {
        if (ObjectUtil.isEmpty(erpTaskList)) {
            return;
        }
        //ERP同步的单号
        Set<String> erpBillNos = erpTaskList.stream().map(ErpOutTask::getErpNo).collect(Collectors.toSet());
        //ERP同步的数据，转换成MAP
        Map<String, List<ErpOutTask>> erpNoMap = erpTaskList.stream().collect(Collectors.groupingBy(ErpOutTask::getErpNo));

        //根据ERP查询出已存在WMS的单据
        List<SoMaster> oldSoMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", erpBillNos));
        Map<String, SoMaster> oldSoMasterMap = CollectionUtils.convertMap(oldSoMasterList, SoMaster::getBillNo);
        Set<String> oldBillNos = oldSoMasterList.stream().map(SoMaster::getBillNo).collect(Collectors.toSet());

        Integer wareId = 286; //写死，卓品仓库
        WareInfo wareInfo = wareInfoService.getById(wareId);
        List<SoDetail> soDetails = new ArrayList<>();
        List<SoMaster> soMasters = new ArrayList<>();
        List<SoDetail> updateSoDetails = new ArrayList<>();
        List<SoDetail> deleteSoDetails = new ArrayList<>();
        for (String erpNo : erpNoMap.keySet()) {
            List<ErpOutTask> erpTasks = erpNoMap.get(erpNo);
            //判断是否已经有值
            if (!oldBillNos.contains(erpNo)) {
                //没有现成的单据，需要新建
                SoMaster soMaster = encapsulationErpMaster(billType, wareInfo, erpNo, erpTasks);
                for (ErpOutTask erpTask : erpTasks) {
                    SoDetail asnDetail = encapsulationErpDetail(soMaster, erpTask);
                    soDetails.add(asnDetail);
                }
                soMasters.add(soMaster);
            } else {
                //已存在单据
                SoMaster soMaster = oldSoMasterMap.get(erpNo);
                //可能需要更新行
                List<SoDetail> oldAsnDetails = soDetailService.getListByField("bill_no", erpNo);
                Map<String, SoDetail> oldAsnDetailMap = CollectionUtils.convertMap(oldAsnDetails, SoDetail::getDetailNo);
                Set<Integer> oldErpLineSet = CollectionUtils.convertSet(oldAsnDetails, SoDetail::getErpLineNo);

                for (ErpOutTask erpTask : erpTasks) {
                    SoDetail soDetail = oldAsnDetailMap.get(erpNo + "-" + erpTask.getErpLineNo());
                    if (soDetail == null) {
                        //不存在 新增
                        SoDetail newAsnDetail = encapsulationErpDetail(soMaster, erpTask);
                        soDetails.add(newAsnDetail);
                    } else {
                        //修改
                        //只允许修改
                        Double erpQty;
                        if (ObjectUtil.equal(ErpOutConstant.ERP_OUT_TYPE_ASNRET, soMaster.getSoType())) {
                            //销售退料
                            erpQty = erpTask.getRtnDeductQtyTU() + erpTask.getRtnFillQtyTU();
                        } else if (ObjectUtil.equals(ErpOutConstant.ERP_OUT_TYPE_SALES, soMaster.getSoType())) {
                            erpQty = erpTask.getQty();
                        } else {
                            erpQty = erpTask.getQtyTrans();
                        }
                        if (ObjectUtil.notEqual(erpQty, soDetail.getOrderQuantity())) {
                            if (soDetail.getPickQuantity() <= erpQty) {
                                soDetail.setOrderQuantity(erpQty);
                                updateSoDetails.add(soDetail);
                            }
                        }
                    }

                    //删除
                    oldErpLineSet.remove(erpTask.getErpLineNo());
                }

                for (Integer erpLine : oldErpLineSet) {
                    SoDetail asnDetail = oldAsnDetailMap.get(erpNo + "-" + erpLine);
                    asnDetail.setState(WareTaskConstant.OUT_STATE_CLOSE2);
                    deleteSoDetails.add(asnDetail);
                }
            }
        }

        soMasterService.saveBatch(soMasters);
        soDetailService.saveBatch(soDetails);
        soDetailService.updateBatchById(updateSoDetails);
        soDetailService.updateBatchById(deleteSoDetails);
    }

    private SoMaster encapsulationErpMaster(Integer billType, WareInfo wareInfo, String erpNo, List<ErpOutTask> erpTasks) {
        //新增
        SoMaster soMaster = new SoMaster();
        //仓库id
        soMaster.setWareId(wareInfo.getWareId()); //仓库id
        soMaster.setWareCode(wareInfo.getWareCode()); //仓库编码
        soMaster.setWareName(wareInfo.getWareName()); //仓库名称
        soMaster.setOrganizationId(-1);
        soMaster.setOrganizationName("自有");
        soMaster.setOrganizationCode("SYS_MINE");
//        soMaster.setBillSource(0);
        soMaster.setSoType(billType);
        soMaster.setBillNo(erpNo);//单据编号
        soMaster.setCreateUserName(StringUtils.isNotEmpty(erpTasks.get(0).getMakeEmpNo()) ? erpTasks.get(0).getMakeEmpNo() : "sys");
        soMaster.setCreateTime(DateUtil.now());
        soMaster.setState(WareTaskConstant.OUT_STATE_INIT);//单据状态
        if (StringUtils.isNotEmpty(erpTasks.get(0).getWldwNo())) {
            Customer customer = customerService.getOneByField("customer_code", erpTasks.get(0).getWldwNo());
            if (ObjectUtil.isNull(customer)) {
//                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "存在供应商不存在WMS，请先同步");
            } else {
                soMaster.setCustomerId(customer.getCustomerId());//供应商ID
                soMaster.setCustomerName(customer.getCustomerName());
            }
        }
        return soMaster;
    }

    private SoDetail encapsulationErpDetail(SoMaster soMaster, ErpOutTask erpTask) {
        SoDetail soDetail = new SoDetail();
        soDetail.setBillNo(soMaster.getBillNo());//单号
        soDetail.setPackDetailId(167);//基本单位ID
        soDetail.setPackDescribe("PCS");//单位
        soDetail.setTransRatio(1.0);
        soDetail.setDetailNo(soMaster.getBillNo()+"-"+ erpTask.getErpLineNo());//asn详情单号
        soDetail.setDocumentsId(erpTask.getId());//单据ID
        soDetail.setErpLine(erpTask.getErpLine());//单行ID
        soDetail.setErpLineNo(erpTask.getErpLineNo());//单行号
        soDetail.setCreateTime(erpTask.getMakeDate());//制单时间
        soDetail.setMakeEmpNo(erpTask.getMakeEmpNo());//制单员工号
        soDetail.setWldwNo(erpTask.getWldwNo());//客户编码
        //物料编码可能不存在
        ItemInfo itemInfo = itemInfoService.getOneByField("item_code", erpTask.getItemCode());
        if (itemInfo == null) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "存在新物料，请先同步物料");
        }
        soDetail.setItemCode(itemInfo.getItemCode());//物料编码
        soDetail.setItemName(itemInfo.getItemName());//物料名称
        if (ObjectUtil.equals(ErpOutConstant.ERP_OUT_TYPE_ASNRET, soMaster.getSoType())) {
            soDetail.setOrderQuantity(erpTask.getRtnDeductQtyTU() + erpTask.getRtnFillQtyTU());
        } else if(ObjectUtil.equals(ErpOutConstant.ERP_OUT_TYPE_SALES, soMaster.getSoType())){
            soDetail.setOrderQuantity(erpTask.getQty());
        } else {
            soDetail.setOrderQuantity(erpTask.getQtyTrans());
        }

        soDetail.setUnitName(erpTask.getUnitName());//采购单位
        soDetail.setSrcDocLine(erpTask.getSrcDocLine());//来源采购单据号
        soDetail.setSrcDocLineNo(erpTask.getSrcDocLineNo());//来源采购订单据行号

        soDetail.setMo(erpTask.getMo());//生产订单ID
        soDetail.setMoPick(erpTask.getMoPick());//生产订单备料ID

        soDetail.setStatus(erpTask.getStatus());//状态
        soDetail.setOrg(erpTask.getOrg());//组织ID
        soDetail.setState(0);

        return soDetail;
    }

    public LocalDateTime getStringLocalDateTime(String str){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime dateTime = LocalDateTime.parse(str.replace('T',' '), formatter);
        return dateTime;
    }

    /**
     * 调拨申请单查询接口
     *
     * @param hashMap 条件
     */
    @Override
    public void addTransferRequestForm(Map<String, Object> hashMap) {
        //获取调拨申请单查询接口
        List<ErpOutTask> erpOutTasks = erpService.inAllocatingOutboundApplication(hashMap);
        this.saveBathErpForZP(erpOutTasks, ErpOutConstant.ERP_OUT_TYPE_OUTSOURCE);
    }

    /**
     * 如果没有获取到数据调用该方法
     *
     * @param soType
     */
    public void deleteSo(int soType) {
        List<SoDetail> soDetailList = soDetailMapper.queryList2(null, null, soType);
        if (soDetailList.size() > 0) {
            soDetailList.stream().forEach(t -> {
                //删除so详情表数据
                soDetailMapper.deleteByBillNoUda1(t.getBillNo(), t.getErpLineNo());
                //查询so详情表是否没有数据了
                List<SoDetail> soDetails = soDetailMapper.selectBillNo(t.getBillNo());
                if (soDetails.size() == 0) {
                    //删除so表数据
                    soMasterMapper.deleteByBillNo(t.getBillNo());
                }
            });
        }
    }

    public boolean equal(double a, double b) {
        if ((a - b > -0.000001) && (a - b) < 0.000001)
            return true;
        else
            return false;
    }
    /**
     * 杂发
     *
     * @param hashMap
     */
    @Override
    public void miscellaneousHair(Map<String, Object> hashMap) {
        //修改库存
        Inventory inventory = inventoryMapper.selectById(hashMap.get("inventoryId").toString());
        inventory.setItemCode(hashMap.get("itemCode").toString());
        //查询物料编码
        ItemInfo item = itemInfoService.getOne(new LambdaQueryWrapper<ItemInfo>().eq(ItemInfo::getItemCode, hashMap.get("itemCode").toString()));
        inventory.setItemName(item.getItemName());
        inventory.setWareId(Integer.parseInt(hashMap.get("wareId").toString()));
        WareInfo ware = wareInfoService.getOne(new LambdaQueryWrapper<WareInfo>().eq(WareInfo::getWareId, Integer.parseInt(hashMap.get("wareId").toString())));
        inventory.setWareName(ware.getWareName());
        inventory.setTransRatio(1d);
//        Double quantity = Double.parseDouble(hashMap.get("quantity").toString());
        Double quantity = inventory.getQuantity();
        Double allotQuantity = Double.parseDouble(hashMap.get("allotQuantity").toString());
        if (allotQuantity.doubleValue() > quantity.doubleValue()) {
            throw new ServiceException(CommonCode.SYSTEM_ERROR, "库存数量小于杂收数量");
        }
        String cellCode = hashMap.get("cellCode").toString();
        inventory.setContainerCode(cellCode);
        inventory.setCellCode(cellCode);
//        inventory.setQuantity(quantity);
        if (inventory.getAllotQuantity() == null) {
            inventory.setAllotQuantity(0d);
        }
        inventory.setAllotQuantity(allotQuantity + inventory.getAllotQuantity());
        int row = inventoryMapper.updateById(inventory);
        if (row <= 0) {
            throw new ServiceException(CommonCode.SYSTEM_ERROR, "修改库存失败");
        }
        //保存出库记录
        SoLog soLog = new SoLog();
        soLog.setWareId(ware.getWareId());
        soLog.setWareName(ware.getWareName());
        soLog.setShipCode(hashMap.get("itemCode").toString());
        soLog.setShipBillCode(hashMap.get("itemName").toString());
        soLog.setPickCellCode(cellCode);
        soLog.setWeight(allotQuantity);
        soLog.setStatus(5);//杂发
        soLog.setCreateTime(DateUtils.now());
        soLog.setCreateUserName(hashMap.get("userName").toString());
        soLogService.save(soLog);
        //杂发回调
        List<MiscellaneousVo> miscellaneousVos = new ArrayList<>();
        MiscellaneousVo miscellaneousVo = new MiscellaneousVo();
        miscellaneousVo.setDocType("MiscShip001");
        List<LinesDtoVo> linesList = new ArrayList<>();
        LinesDtoVo lines = new LinesDtoVo();
        lines.setItemCode(hashMap.get("itemCode").toString());
        //获取库区编码
        LambdaQueryWrapper<CellInfo> cellInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        cellInfoLambdaQueryWrapper.eq(CellInfo::getCellCode, cellCode);
        CellInfo one = cellInfoService.getOne(cellInfoLambdaQueryWrapper);
        if (one == null) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "库位为空");
        }
        ShelfInfo shelfInfo = shelfInfoMapper.selectById(one.getShelfInfoId());
        if (shelfInfo == null) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "库位组为空");
        }
        AreaInfo areaInfo = areaInfoMapper.selectById(shelfInfo.getAreaId());
        if (areaInfo == null) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "库区为空");
        }
        lines.setWhCode(areaInfo.getAreaCode());
        lines.setStoreQty(allotQuantity);//杂收数量
        linesList.add(lines);
        miscellaneousVo.setLines(linesList);
        miscellaneousVos.add(miscellaneousVo);
        Map<String, Object> returnMap = new HashMap<>();
        /*try {
            returnMap = doPostOrGet("http://61.160.125.186:5555/zp/api/ZpViewMiscShip/Create", JSONObject.toJSONString(miscellaneousVos));
            if (returnMap.get("code") == null || !"200".equals(returnMap.get("code").toString())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "回传ERP杂发单失败："+returnMap.get("msg") );
            }
        } finally {
            soMasterServiceImpl.erpLog(returnMap, 503);
        }*/

    }

    /**
     * 同步拉取
     *
     * @param soMaster
     */
    @Override
    public void synchronous(SoMaster soMaster) {
        List<SoDetail> allSoDetails = new ArrayList<>();
        List<SoMaster> soMasters = new ArrayList<>();
        soMasters.add(soMaster);
        List<SoDetail> newSoDetails = soDetailService.syncCurrentData(soMasters);
        if (ObjectUtil.isEmpty(newSoDetails)) {
            newSoDetails = new ArrayList<SoDetail>();
        }
        List<SoDetail> oldSoDetails = soDetailService.list(new QueryWrapper<SoDetail>().eq("bill_no", soMaster.getBillNo()));
        if (ObjectUtil.isEmpty(oldSoDetails)) {
            oldSoDetails = new ArrayList<SoDetail>();
        }
        //对应波次详情
        //老单子新单子合并
        allSoDetails.addAll(oldSoDetails);
        allSoDetails.addAll(newSoDetails);
        //行号可能重复，不能作为唯一条件去重
        Map<SoDetail, SoDetail> newMap = newSoDetails.stream()
                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
        //新单子老单子合并
        Map<SoDetail, SoDetail> oldMap = oldSoDetails.stream()
                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
        //3.根据明细行去获取
        soDetailService.contrastSoDetail(allSoDetails, newMap, oldMap);
    }

    @Autowired
    private SoMasterServiceImpl soMasterServiceImpl;


}
